package online.inote.naruto.api.access.admin.modules.system.service;

import com.alibaba.fastjson.JSON;
import online.inote.naruto.api.access.admin.modules.system.entity.ApiEntity;
import online.inote.naruto.api.access.admin.modules.system.entity.AuthInterfaceEntity;
import online.inote.naruto.api.access.admin.modules.system.entity.SystemEntity;
import online.inote.naruto.api.access.admin.modules.system.repository.ApiRepository;
import online.inote.naruto.api.access.props.ApiAccessProperties;
import online.inote.naruto.cache.CacheSupport;
import online.inote.naruto.utils.Assert;
import online.inote.naruto.utils.DateTimeUtils;
import online.inote.naruto.utils.Page;
import online.inote.naruto.utils.StringUtils;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @description API Service
 * @author XQF.Sui
 * @date 2021/08/05 20:38
 */
@Service
@Transactional(rollbackFor = RuntimeException.class)
public class ApiService {

  private final ApiRepository repository;
  private final ApiAccessProperties apiProps;
  private final AuthInterfaceService authInterfaceService;

  public ApiService(
      ApiRepository repository,
      ApiAccessProperties apiProps,
      AuthInterfaceService authInterfaceService) {
    this.repository = repository;
    this.apiProps = apiProps;
    this.authInterfaceService = authInterfaceService;
  }

  public void save(ApiEntity api) {
    if (StringUtils.isBlank(api.getId())) {
      api.setId(UUID.randomUUID().toString());
      api.setCreateTime(DateTimeUtils.getNow());
    }

    api.genSignatureDigest();

    if (apiProps.getDatabase().getEnable()) {
      List<ApiEntity> apiEntities =
          repository.findAllByTypeAndMethod(api.getType(), api.getMethod());

      if (CollectionUtils.isEmpty(apiEntities)) {
        repository.save(api);
      }
    }

    CacheSupport.cache(
        apiProps.getCache().initInterfaceInfoCacheKey(api.getId()), JSON.toJSONString(api));
  }

  public Optional<ApiEntity> details(String id) {
    return repository.findById(id);
  }

  public void getPage(Page<ApiEntity> page) {
    Example<ApiEntity> example;

    ApiEntity params = page.getSearchParams();

    if (Objects.nonNull(params)) {
      example = Example.of(page.getSearchParams());
    } else {
      example = Example.of(new ApiEntity());
    }

    Sort sort = Sort.by(ApiEntity.Fields.createTime).descending();
    PageRequest request = PageRequest.of(page.getEsPage(), page.getRows(), sort);
    org.springframework.data.domain.Page<ApiEntity> resultPage =
        repository.findAll(example, request);

    page.setRecords(resultPage.getTotalElements());
    page.setDataList(resultPage.getContent());

    if (CollectionUtils.isEmpty(page.getDataList())) {
      return;
    }

    page.getDataList()
        .forEach(
            api -> {
              api.setAuthSystemNumber(
                  CacheSupport.count(
                      apiProps.getCache().initInterfaceAuthSystemCacheKey(api.getId())));

              if (StringUtils.isNotBlank(params.getSystemId())) {
                api.setIsAuth(
                    CacheSupport.isMember(
                        apiProps.getCache().initInterfaceAuthSystemCacheKey(api.getId()),
                        params.getSystemId()));
              }
            });
  }

  public void enableSystemCacheHandle(SystemEntity system) {
    Assert.notBlank(system.getId(), "系统ID不能为空");

    if (system.getEnable()) {
      // 将授权接口集合增加到缓存中
      List<AuthInterfaceEntity> aieEntities = authInterfaceService.findBySystemId(system.getId());

      if (!CollectionUtils.isEmpty(aieEntities)) {
        List<String> interfaceIdList =
            aieEntities.stream().map(AuthInterfaceEntity::getApiId).collect(Collectors.toList());

        List<ApiEntity> apiEntities = repository.findAllById(interfaceIdList);

        if (!CollectionUtils.isEmpty(apiEntities)) {
          Set<String> methodSet =
              apiEntities.stream().map(ApiEntity::getClassMethod).collect(Collectors.toSet());
          CacheSupport.addSet(
              apiProps.getCache().initSystemAuthInterfacePathCacheKey(system.getId()), methodSet);
        }
      }
    } else {
      CacheSupport.delete(apiProps.getCache().initSystemAuthInterfacePathCacheKey(system.getId()));
    }
  }
}
